﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using ZxZOnlineExam.Dtos.ZxZUser;
using ZxZOnlineExam.Models;
using ZxZOnlineExam.WebApi.Tools.Pagination;

namespace ZxZOnlineExam.WebApi.Controllers
{
    [Authorize]
    [Route("api/auth")]
    [ApiController]
    public class AuthenticationController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly UserManager<ZxZUser> _userManager;
        private readonly SignInManager<ZxZUser> _signInManager;
        private readonly RoleManager<ZxZRole> _roleManager;
        private readonly IMapper _mapper;

        public AuthenticationController(IConfiguration configuration,
            UserManager<ZxZUser> userManager,
            SignInManager<ZxZUser> signInManager,
            RoleManager<ZxZRole> roleManager,
            IMapper mapper)
        {
            _configuration = configuration;
            _userManager = userManager;
            _signInManager = signInManager;
            this._roleManager = roleManager;
            this._mapper = mapper;
        }

        #region Login And Register

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="loginDto"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginDto loginDto)
        {
            //1.验证用户名密码===========>>>>>>>>此时从后台拿到的password不应该是明文，就该为base64加密字符串，后台拿到之后解密字符串
            var loginResult = await _signInManager.PasswordSignInAsync(
                loginDto.UserName,
                loginDto.Password,
                loginDto.IsRemember,
                false
                );
            if (!loginResult.Succeeded)
            {
                return BadRequest("用户名或密码错误，登录失败！");
            }
            var user = await _userManager.FindByNameAsync(loginDto.UserName);

            //2.创建jwt
            //header
            var signingAlgorithm = SecurityAlgorithms.HmacSha256;
            //payload
            var claims = new List<Claim>
            {
                // sub
                new Claim(JwtRegisteredClaimNames.Sub,user.Id),
                //new Claim(ClaimTypes.Role,"Admin")

            };
            var roleNames = await _userManager.GetRolesAsync(user);
            foreach (var roleName in roleNames)
            {
                var roleClaim = new Claim(ClaimTypes.Role, roleName);
                claims.Add(roleClaim);
            }
            //signiture
            var secretByte = Encoding.UTF8.GetBytes(_configuration["Authentication:Secretkey"]);
            var signingkey = new SymmetricSecurityKey(secretByte);
            var signingCredentials = new SigningCredentials(signingkey, signingAlgorithm);

            var token = new JwtSecurityToken(
                issuer: _configuration["Authentication:Issuer"],
                audience: _configuration["Authentication:Audience"],
                claims,
                notBefore: DateTime.UtcNow,
                expires: DateTime.UtcNow.AddDays(1),//设置20分钟后过期
                signingCredentials
            );
            var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);


            //3 return 200 ok + jwt
            //找到当前Login对象的详细信息，并封装成Dto返回给前台
            return Ok(new ZxZUserDto(){
                Id=user.Id,UserName=user.UserName,Nickname=user.Nickname,Jwt=tokenStr
            });
        }


        /// <summary>
        /// 注册Student用户
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("register")]
        public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
        {
            //1.使用用户名创建用户对象
            var user = new ZxZUser()
            {
                UserName = registerDto.UserName
            };
            //2.hash密码，保存用户
            var result = await _userManager.CreateAsync(user, registerDto.Password);
            if (!result.Succeeded)
            {
                return BadRequest(result.Errors);
            }

            //3.将用户添加到指定的Role中;
            await _userManager.AddToRoleAsync(user, "Student");

            //4.return
            return Ok();
        }

        /// <summary>
        /// 注册Teacher/Admin用户
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        [Authorize(Roles ="Admin")]
        [HttpPost("registerByRole")]
        public async Task<IActionResult> RegisterByRole([FromBody] RegisterDto registerDto)
        {
            //1.使用用户名创建用户对象
            var user = new ZxZUser()
            {
                UserName = registerDto.UserName
            };
            //2.hash密码，保存用户
            var result = await _userManager.CreateAsync(user, registerDto.Password);
            if (!result.Succeeded)
            {
                return BadRequest();
            }

            //3.将用户添加到指定的Role中;
            var roleResult = await _userManager.AddToRoleAsync(user, registerDto.RoleName);
            if (!roleResult.Succeeded)
            {
                return BadRequest();
            }
            //4.return
            return Ok();


        }

        #endregion

        //Role已经在初始数据时完全指定，故此处不再单独对Role进行CRUD

        #region ZxZ用户操作
        //Get操作：全部、单个、指定查询条件、分页、指定查询条件+分页

        /// <summary>
        /// GetAll
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("user")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> GetAll()
        {
            var result = _userManager.Users.AsQueryable();
            return Ok(_mapper.Map<List<ZxZUserDto>>(await result.ToListAsync()));
        }

        /// <summary>
        /// GetAll
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("user/{userId}")]
        public async Task<IActionResult> GetSingle([FromRoute]string userId)   
        {
            var result =await _userManager.FindByIdAsync(userId);
            if (result==null)
            {
                return BadRequest("未找到指定对象");
            }
            return Ok(_mapper.Map<ZxZUserDto>(result));
        }

        /// <summary>
        /// 设定此时可以通过：Username、昵称、班级、角色等进行查询
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("userbyQuery")]
        public async Task<IActionResult> GetByQuery([FromQuery]ZxZUserDtoForQuery zxZUserDtoForQuery)
        {
            //1.拿到IQueryable根数据
            var user = _userManager.Users.AsQueryable();
            //2.按要求进行查询
            if (zxZUserDtoForQuery.Username!=null&&zxZUserDtoForQuery.Username!="")
            {
                user = user.Where(u => u.UserName == zxZUserDtoForQuery.Username);
            }
            if (zxZUserDtoForQuery.Nickname!=null&&zxZUserDtoForQuery.Nickname!="")
            {
                user = user.Where(u => u.Nickname.Contains(zxZUserDtoForQuery.Nickname));
            }
            //班级暂时没写2022年1月14日19:27:51
            var _user = new List<ZxZUser>();
            if (zxZUserDtoForQuery.RoleName != null && zxZUserDtoForQuery.RoleName != "")
            {
                //user = user.Where(async u => await _userManager.IsInRoleAsync(u, zxZUserDtoForQuery.RoleName));
                
                foreach (var item in user.ToList())
                {
                    if (await _userManager.IsInRoleAsync(item,zxZUserDtoForQuery.RoleName))
                    {
                        _user.Add(item);
                    }
                }
                //if (_user.Count>0)
                //{
                //    user = _user.AsQueryable();
                //}
            }
            //var data = await user.ToListAsync();
            return Ok(_mapper.Map<List<ZxZUserDto>>(_user));
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="pagination"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("userbyPagination")]
        public async Task<IActionResult> GetUserByPagnation([FromBody]Pagination pagination)
        {
            var result = _userManager.Users.AsQueryable();
            result = result.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize);
            //return Ok(_mapper.Map<List<ZxZUserDto>>(await result.ToListAsync()));
            pagination.Total = result.Count();
            //user = user.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize);

            pagination.Data = _mapper.Map<List<ZxZUserDto>>(await result.ToListAsync());
            return Ok(pagination);
        }

        /// <summary>
        /// 先按条件查询，然后再分页
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("userbyQueryAndPagination")]
        public async Task<IActionResult> GetByQueryAndPagination([FromQuery] ZxZUserDtoForQuery zxZUserDtoForQuery,[FromBody] Pagination pagination)
        {
            //1.拿到IQueryable根数据
            var user = _userManager.Users;
            //2.按要求进行查询
            if (zxZUserDtoForQuery.Username != null && zxZUserDtoForQuery.Username != "")
            {
                user = user.Where(u => u.UserName == zxZUserDtoForQuery.Username);
            }
            if (zxZUserDtoForQuery.Nickname != null && zxZUserDtoForQuery.Nickname != "")
            {
                user = user.Where(u => u.Nickname.Contains(zxZUserDtoForQuery.Nickname));
            }
            //班级暂时没写2022年1月14日19:27:51
            
            if (zxZUserDtoForQuery.RoleName != null && zxZUserDtoForQuery.RoleName != "")
            {
                //user = user.Where(async u => await _userManager.IsInRoleAsync(u, zxZUserDtoForQuery.RoleName));
                var _user = new List<ZxZUser>();
                foreach (var item in user.ToList())
                {
                    if (await _userManager.IsInRoleAsync(item, zxZUserDtoForQuery.RoleName))
                    {
                        _user.Add(item);
                    }
                }
                //user = (IQueryable<ZxZUser>)_user;
                if (_user.Count>0)
                {
                    user = _user.AsQueryable();
                }
            }

            pagination.Total = user.Count();
            user = user.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize);
            
            pagination.Data = _mapper.Map<List<ZxZUserDto>>(await user.ToListAsync());
            return Ok(pagination);
        }


        //Create操作已经写在Register中

        //Update操作：修改指定用户的基本信息、升级、降级、修改密码
        /// <summary>
        /// Admin 修改指定User的基本信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="zxZUserDtoForUpdate"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user/{userId}")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> UpdateUserInfoByAdmin([FromRoute]string userId,[FromBody]ZxZUserDtoForUpdate zxZUserDtoForUpdate )
        {
            //Admin可以修改全局信息
            //1.找到指定对象
            var result = await _userManager.FindByIdAsync(userId);
            if (result==null)
            {
                return BadRequest("未找到指定对象");
            }
            //2.更新数据
            result.Address = zxZUserDtoForUpdate.Address;
            result.HeadPortrait = zxZUserDtoForUpdate.HeadPortrait;
            result.Nickname = zxZUserDtoForUpdate.Nickname;
            result.Introduction = zxZUserDtoForUpdate.Introduction;
            //3.存储并返回新的User对象
            var identityResult=await _userManager.UpdateAsync(result);
            if (!identityResult.Succeeded)
            {
                return BadRequest("服务器错误，修改失败");
            }
            return Ok(_mapper.Map<ZxZUserDto>(result));
        }
        /// <summary>
        /// 当前登录用户 修改自己的基本信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="zxZUserDtoForUpdate"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user")]
        //[Authorize(Roles = "Admin")]
        public async Task<IActionResult> UpdateUserInfo([FromBody] ZxZUserDtoForUpdate zxZUserDtoForUpdate)
        {
            //Admin可以修改全局信息
            //1.找到指定对象
            //var result = await _userManager.FindByIdAsync(userId);
            var result = await _userManager.FindByNameAsync(User.Identity.Name);
            if (result == null)
            {
                return BadRequest("未找到指定对象");
            }
            //2.更新数据
            result.Address = zxZUserDtoForUpdate.Address;
            result.HeadPortrait = zxZUserDtoForUpdate.HeadPortrait;
            result.Nickname = zxZUserDtoForUpdate.Nickname;
            result.Introduction = zxZUserDtoForUpdate.Introduction;
            //3.存储并返回新的User对象
            var identityResult = await _userManager.UpdateAsync(result);
            if (!identityResult.Succeeded)
            {
                return BadRequest("服务器错误，修改失败");
            }
            return Ok(_mapper.Map<ZxZUserDto>(result));
        }

        /// <summary>
        /// Upgrade   考虑到角色和用户之前是多对多的关系，那么就从前台传加oldrolename和newrolename
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="zxZUserDtoForUpdate"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user/{userId}/role")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> UpdateUserRole([FromRoute]string userId,[FromBody]ZxZUserDtoForUpdate zxZUserDtoForUpdate)
        {
            //1.找到指定对象
            var result = await _userManager.FindByIdAsync(userId);
            var oldRole = await _roleManager.FindByNameAsync(zxZUserDtoForUpdate.OldRoleName);
            var newRole = await _roleManager.FindByNameAsync(zxZUserDtoForUpdate.NewRoleName);
            if (result==null||oldRole==null||newRole==null)
            {
                return BadRequest("未找到指定对象！");
            }
            //2.将对象从当前角色中删除，再将其加到高一级角色中
            var oldRoleResult= await _userManager.RemoveFromRoleAsync(result, oldRole.Name);
            var newRoleResult= await _userManager.AddToRoleAsync(result, newRole.Name);

            //3.存储并返回新的User对象
            //var identityResult = await _userManager.UpdateAsync(result);
            if (!oldRoleResult.Succeeded||!newRoleResult.Succeeded)
            {
                return BadRequest("服务器错误，修改失败");
            }
            return Ok(_mapper.Map<ZxZUserDto>(result));
        }

        /// <summary>
        /// 管理员理更新任意指定的除管理员身份的用户密码
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="zxZUserDtoForUpdate"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user/{userId}/pwd")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> ChangePasswordByAdmin([FromRoute]string userId, [FromBody] ZxZUserDtoForChangePassword zxZUserDtoForChangePassword)
        {
            //1.找到指定对象
            var result = await _userManager.FindByIdAsync(userId);
            if (result == null)
            {
                return BadRequest("未找到指定对象");
            }
            //找到指定对象的Role,管理员角色的用户密码不可被操作
            if (await _userManager.IsInRoleAsync(result,"Admin"))
            {
                return BadRequest("不可以操作其他管理员的密码");
            }
            //2.更新数据
            var identityResult = await _userManager.ChangePasswordAsync(result, zxZUserDtoForChangePassword.OldPassword, zxZUserDtoForChangePassword.NewPassword);
            
            //3.存储并返回新的User对象
            
            if (!identityResult.Succeeded)
            {
                return BadRequest(identityResult.Errors);
            }
            return Ok(_mapper.Map<ZxZUserDto>(result));
        }

        /// <summary>
        /// 当前登陆用户更改自己的密码
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="zxZUserDtoForUpdate"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user/pwd")]
        //[Authorize(Roles = "Admin")]
        public async Task<IActionResult> ChangePassword([FromBody] ZxZUserDtoForChangePassword zxZUserDtoForChangePassword)
        {
            //1.找到指定对象
            //var result = await _userManager.FindByIdAsync(userId);
            //if (result == null)
            //{
            //    return BadRequest("未找到指定对象");
            //}
            var user = await _userManager.FindByNameAsync(User.Identity.Name);
            ////找到指定对象的Role,管理员角色的用户密码不可被操作
            //if (await _userManager.IsInRoleAsync(result, "Admin"))
            //{
            //    return BadRequest("不可以操作其他管理员的密码");
            //}
            //2.更新数据
            var identityResult = await _userManager.ChangePasswordAsync(user, zxZUserDtoForChangePassword.OldPassword, zxZUserDtoForChangePassword.NewPassword);

            //3.存储并返回新的User对象

            if (!identityResult.Succeeded)
            {
                return BadRequest("服务器错误，修改失败");
            }
            return Ok(_mapper.Map<ZxZUserDto>(user));
        }


        //Delete操作：删除单个、删除多个

        [HttpDelete]
        [Route("user")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> DeleteUser([FromBody] List<string> userIds
            //string[] userIds
            )
        {
            //1.先找到要删除的用户集合
            List<ZxZUser> zxZUsers = new List<ZxZUser>();
            foreach (var item in userIds)
            {
                var user = await _userManager.FindByIdAsync(item);
                if (user!=null)
                {
                    zxZUsers.Add(user);
                }
            }
            //2.执行删除
            foreach (var item in zxZUsers)
            {
                await _userManager.DeleteAsync(item);
            }
            return NoContent();
        }

        [HttpDelete("user/{id}")]
        //[Route("user/{id}")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> DeleteSingleUser([FromRoute]string id
            )
        {     
            ////1.先找到要删除的用户集合
            //List<ZxZUser> zxZUsers = new List<ZxZUser>();
            //foreach (var item in userIds)
            //{
            //    var user = await _userManager.FindByIdAsync(item);
            //    if (user != null)
            //    {
            //        zxZUsers.Add(user);
            //    }
            //}
             var user = await _userManager.FindByIdAsync(id);
            if (user==null)
            {
                return BadRequest("找不到指定对象！");
            }
            //2.执行删除
            //foreach (var item in zxZUsers)
            //{
            //    await _userManager.DeleteAsync(item);
            //}
            var result = await _userManager.DeleteAsync(user);
            if (!result.Succeeded)
            {
                return BadRequest("服务器错误，删除失败！");
            }
            return NoContent();
        }
        #endregion
    }
}
